use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::{
    Class, ClassAttributeBuilder, ClassBuilder, ClassGetter, ClassRelationBuilder,
    RelationRelatedType, ValueType,
};
use crate::modeling::{
    ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder, ClassPersistenceGetter,
    ClassRelation, ClassRelationGetter, Value,
};

use super::{FormSchema, ModelProvider};

const MODEL_CLASS_IDENTIFIER: &'static str = "g01_model";

const MODEL_CLASS_NAME: &'static str = "model";

const MODEL_TABLE_NAME: &'static str = "_g01_meta_models";

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum ModelType {
    /// LLM
    #[default]
    #[serde(rename = "llm")]
    LLM,
    /// TextEmbedding
    #[serde(rename = "text-embedding")]
    TextEmbedding,
    /// TextGeneration
    #[serde(rename = "text-generation")]
    TextGeneration,
    /// SpeechToText
    #[serde(rename = "speech2text")]
    SpeechToText,
    /// Moderation
    #[serde(rename = "moderation")]
    Moderation,
    /// Moderation
    #[serde(rename = "tts")]
    TTS,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "ModelBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct Model {
    /// id
    pub id: i64,
    ///
    pub provider_identifier: String,
    /// identifier
    pub identifier: String,
    /// 名称
    pub name: String,
    /// 名称
    pub title: String,
    /// 图标
    pub icon: Option<String>,
    /// 类型
    pub model_type: ModelType,
    /// deprecated
    pub deprecated: bool,
    /// 功能
    pub features: String,
    ///
    pub fetch_from: String,
    /// 选项
    pub options: Option<String>,
    /// 备注
    pub description: String,
    /// 创建时间
    pub created_at: i64,
    /// 更新时间
    pub updated_at: i64,

    pub credential_schema: Option<FormSchema>,
}

impl ValueMapper for Model {}
//
crate::impl_from_value!(Model);
crate::impl_class_persistence_getter!(Model, MODEL_TABLE_NAME);
crate::impl_class_relations_getter!(
    Model,
    vec![ClassRelationBuilder::default()
        .src_identifier(ModelProvider::get_identifier()?)
        .target_identifier(Self::get_identifier()?)
        .related_type(RelationRelatedType::Keys)
        .related_at("provider_identifier")
        .build()?]
);

impl ClassGetter for Model {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(MODEL_CLASS_NAME))
    }
    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(MODEL_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(MODEL_CLASS_IDENTIFIER);

        let mut commons = crate::modeling::common_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("provider_identifier")
                .title("供应商")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("model_type")
                .title("类型")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("deprecated")
                .title("deprecated")
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("features")
                .title("功能")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("fetch_from")
                .title("fetch_from")
                .data_type(ValueType::String)
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));

        let clazz = ClassBuilder::default()
            .identifier(MODEL_CLASS_IDENTIFIER)
            .name(MODEL_CLASS_NAME)
            .data_is_type(true)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}

impl From<ModelType> for String {
    fn from(value_type: ModelType) -> Self {
        match value_type {
            ModelType::LLM => "llm".into(),
            ModelType::TextEmbedding => "text-embedding".into(),
            ModelType::TextGeneration => "text-generation".into(),
            ModelType::SpeechToText => "speech2text".into(),
            ModelType::Moderation => "moderation".into(),
            ModelType::TTS => "tts".into(),
        }
    }
}

impl From<String> for ModelType {
    fn from(v_type: String) -> Self {
        match v_type {
            v_type if v_type == "llm" => ModelType::LLM,
            v_type if v_type == "text-embedding" => ModelType::TextEmbedding,
            v_type if v_type == "text-generation" => ModelType::TextGeneration,
            v_type if v_type == "speech2text" => ModelType::SpeechToText,
            v_type if v_type == "moderation" => ModelType::Moderation,
            v_type if v_type == "tts" => ModelType::TTS,
            _ => ModelType::LLM,
        }
    }
}
